package com.lord.otter.component.infrastructure.retry.strategy;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.lord.otter.component.infrastructure.retry.constant.ExecModel;
import lombok.AllArgsConstructor;

import java.util.List;

/**
 * 抽象异常处理
 *
 * @author lord
 * 2025/8/15 00:07
 */
@AllArgsConstructor
public abstract class AbstractExceptionHandler {

    /**
     * 不重试的异常 永久性错误
     * <p>
     * 比如：
     * <p>
     * 业务异常，往往这些异常不需要重试
     * <p>
     * 请求地址不存在、方法错误等
     */
    private final List<Class<? extends Exception>> noRetryExceptions;
    /**
     * 需要次幂步长重试的异常
     * <p>
     * 比如：
     * <p>
     * 连接异常，往往这些异常没那么快恢复，需要等待时间长一些
     */
    private final List<Class<? extends Exception>> powStepExceptions;

    /**
     * 异常处理策略
     *
     * @param exception 本次触发的异常
     * @author lord
     * 2025/8/16 22:54
     */
    public RetryParameter handle(Exception exception) {
        if (isNoRetryExceptions(exception, noRetryExceptions)) {
            return handleNoRetryException(exception);
        } else if (isPowStepExceptions(exception, powStepExceptions)) {
            return handlePowStepException(exception);
        } else {
            return handleOtherException(exception);
        }
    }

    /**
     * 判断是否为 不重试的异常 永久性错误
     *
     * @param exception         本次触发的异常
     * @param noRetryExceptions 预先定义的 不重试的异常 永久性错误
     * @author lord
     * 2025/8/16 22:48
     */
    private boolean isNoRetryExceptions(Exception exception, List<Class<? extends Exception>> noRetryExceptions) {
        if (noRetryExceptions == null || noRetryExceptions.isEmpty()) {
            return false;
        }
        Throwable rootCause = ExceptionUtil.getRootCause(exception);
        return noRetryExceptions
                .stream()
                .anyMatch(
                        noRetryException -> noRetryException.isInstance(exception) || noRetryException.isInstance(rootCause)
                );
    }

    /**
     * 判断是否为 需要次幂步长重试的异常（可能长时间无法恢复的异常）
     *
     * @param exception         本次触发的异常
     * @param powStepExceptions 预先定义的 需要次幂步长重试的异常
     * @author lord
     * 2025/8/16 22:48
     */
    private boolean isPowStepExceptions(Exception exception, List<Class<? extends Exception>> powStepExceptions) {
        if (powStepExceptions == null || powStepExceptions.isEmpty()) {
            return false;
        }
        Throwable rootCause = ExceptionUtil.getRootCause(exception);
        return powStepExceptions
                .stream()
                .anyMatch(
                        powStepException -> powStepException.isInstance(exception) || powStepException.isInstance(rootCause)
                );
    }

    /**
     * 处理 不重试的异常 永久性错误
     * 默认不重试，直接往外抛
     *
     * @author lord
     * 2025/8/16 22:50
     */
    protected RetryParameter handleNoRetryException(Exception exception) {
        throw new RuntimeException(exception);
    }

    /**
     * 处理 需要次幂步长重试的异常
     *
     * @author lord
     * 2025/8/16 22:50
     */
    protected RetryParameter handlePowStepException(Exception exception) {
        return RetryParameter.builder()
                .execModel(ExecModel.POW_STEP)
                .delay(60 * 1000L)
                .step(6 * 1000L)
                .maxRetryNumber(6)
                .pow(2)
                .build();
    }

    /**
     * 处理其他异常
     *
     * @author lord
     * 2025/8/16 22:50
     */
    protected RetryParameter handleOtherException(Exception exception) {
        return RetryParameter.builder()
                .execModel(ExecModel.POW_STEP)
                .delay(1000L)
                .step(1000L)
                .maxRetryNumber(6)
                .pow(1)
                .build();
    }
}

